
#include "filelist.h"
#include "os_task.h"
#include "com_api.h"
#include "os_time.h"
//*********************************************************
static filemanage_t  filemp = {
    .total    = 0,
    .head     = NULL,

    .cfg.sort_type     = 0,
    .cfg.search_type   = 0,
    .cfg.end_search_cb = NULL,
};
//*********************************************************
fileNode* file_createNode(fileinfo_t* data) 
{
    fileNode *newNode = (fileNode*)malloc(sizeof(fileNode));
    if(newNode == NULL){
        log_e("err0\n");
        return NULL;
    }

    newNode->data = data;
    newNode->next = NULL;

    return newNode;
}

int file_insertAtHead(fileNode** head,fileinfo_t* data) 
{
    fileNode* newNode = file_createNode(data);
    if(!newNode){
        log_e("err\n");
        return OS_ERR;
    }

    newNode->next = *head;
    *head = newNode;

    return OS_OK;
}

// 在链表尾部插入节点
int file_insertAtTail(fileNode** head,fileinfo_t* data) 
{
    char new_path[1024] = {0};
    char cmp_path[1024] = {0};

    fileNode* newNode = file_createNode(data);
    if(!newNode){
        log_e("err\n");
        return OS_ERR;
    }

    if(*head == NULL){
        newNode->next = *head;
        *head = newNode;
        return OS_OK;
    }

    memset(cmp_path,0,sizeof(cmp_path));
    memset(new_path,0,sizeof(new_path));

    snprintf(new_path,sizeof(new_path),"%s/%s",data->dir,data->name);
    snprintf(cmp_path,sizeof(cmp_path),"%s/%s",(*head)->data->dir,(*head)->data->name);

    if(strcmp(new_path, cmp_path) < 0){
        newNode->next = *head;
        *head = newNode;
        return OS_OK;
    }

    fileNode* current = *head;

    if(filemp.cfg.sort_type == SORT_TYPE_NAME)
    {
        while(current->next != NULL)
        {
            memset(cmp_path,0,sizeof(cmp_path));
            memset(new_path,0,sizeof(new_path));
    
            snprintf(new_path,sizeof(new_path),"%s/%s",data->dir,data->name);
            snprintf(cmp_path,sizeof(cmp_path),"%s/%s",current->next->data->dir,current->next->data->name);
    
            if(strcmp(new_path,cmp_path) < 0)
            {
                break;
            }
    
            current = current->next;
        }
        newNode->next = current->next;
        current->next = newNode;
    }
    else{
        while(current->next != NULL){
            current = current->next;
        }
        current->next = newNode;
    }

    return OS_OK;
}

// 在指定位置插入节点
int file_insertAtPosition(fileNode** head,fileinfo_t* data, int position)
{
    if (position < 0) {
        log_e("err\n");
        return OS_ERR;
    }
    
    if(position == 0){
        file_insertAtHead(head, data);
        return OS_OK;
    }
    
    fileNode *newNode   = file_createNode(data);
    fileNode *current   = *head;
    int currentPosition = 0;
    
    while (current != NULL && currentPosition < position - 1) {
        current = current->next;
        currentPosition++;
    }
    
    if(current == NULL){
        log_e("err\n");
        free(newNode);
        return OS_ERR;
    }
    
    newNode->next = current->next;
    current->next = newNode;

    return OS_OK;
}


int file_deleteAtHead(fileNode **head) 
{
    if(*head == NULL){
        log_e("err\n");
        return OS_ERR;
    }
    
    fileNode *temp = *head;
    *head = (*head)->next;
    free(temp);

    return OS_OK;
}

int file_deleteAtTail(fileNode **head) 
{
    if(*head == NULL){
        log_e("err\n");
        return OS_ERR;
    }
    
    if((*head)->next == NULL){
        free(*head);
        *head = NULL;
        return OS_OK;
    }
    
    fileNode *current = *head;
    while(current->next->next != NULL){
        current = current->next;
    }
    
    free(current->next);
    current->next = NULL;

    return OS_OK;
}


int file_deleteAtPosition(fileNode** head, int position) 
{
    if(*head == NULL || position < 0){
        log_e("err\n");
        return OS_ERR;
    }
    
    if(position == 0){
        file_deleteAtHead(head);
        return OS_ERR;
    }
    
    fileNode *current = *head;
    fileNode *prev    = NULL;
    int currentPosition = 0;
    
    while(current != NULL && currentPosition < position){
        prev = current;
        current = current->next;
        currentPosition++;
    }
    
    if(current == NULL){
        log_e("err\n");
        return OS_ERR;
    }
    
    prev->next = current->next;
    free(current);

    return OS_OK;
}

fileNode* file_search(fileNode* head, int index) 
{
    int length = 0;
    fileNode* current = head;
    while(current != NULL) 
    {
        if(length == index)
        {
            return current;
        }
    }

    return NULL;
}

int file_printList(fileNode* head) 
{
    int filenum = 1;
    fileNode* current = head;
    
    while(current != NULL) 
    {
        log_d("filename:%d:%d:%s:%s\n",filenum++,current->data->type,current->data->dir,current->data->name);
        current = current->next;
    }

    log_i("printflist end\n");
   
    return 0;
}

// 获取链表长度
int file_getLength(fileNode* head) 
{
    int length = 0;
    fileNode* current = head;
    while(current != NULL){
        length++;
        current = current->next;
    }

    return length;
}

// 释放链表内存
int file_freeList(fileNode** head) 
{
    fileNode* current = *head;
    fileNode* next;

    while(current != NULL)
    {
        next = current->next;
        free(current);
        current = next;
    }
    
    *head = NULL;

    return OS_OK;
}

// int main() {
//     fileNode *head = NULL;
    
//     // 测试插入操作
//     file_insertAtTail(&head, 10);
//     file_insertAtTail(&head, 20);
//     file_insertAtHead(&head, 5);
//     file_insertAtPosition(&head, 15, 2);
    
//     file_printList(head);  // 输出: 5 -> 10 -> 15 -> 20 -> NULL
    
//     // 测试查找操作
//     fileNode *found = file_search(head, 15);
//     if (found != NULL) {
//         printf("找到节点: %d\n", found->data);
//     } else {
//         printf("未找到节点\n");
//     }
    
//     // 测试删除操作
//     file_deleteAtHead(&head);
//     file_deleteAtTail(&head);
//     file_deleteAtPosition(&head, 1);
    
//     file_printList(head);  // 输出: 10 -> NULL
    
//     // 测试长度
//     printf("链表长度: %d\n", file_getLength(head));
    
//     // 释放链表
//     file_freeList(&head);
    
//     return 0;
// }

int file_add_list(int type,char* dir,char* name)
{
    int len = 0;
    fileinfo_t* info = NULL;

    if((!dir)||(!name)){
        log_e("err\n");
        return OS_ERR;
    }

    info =(fileinfo_t*)malloc(sizeof(fileinfo_t));
    if(!info){
        log_e("err\n");
        return OS_ERR;
    }

    info->type = type;
    info->dir  = NULL;
    info->name = NULL;

    len = strlen(dir) + 1;
    if(len){
        info->dir = (char*)malloc(len);
        memset(info->dir,0,len);
        snprintf(info->dir,len,"%s",dir);
    }

    len = strlen(name) + 1;
    if(len){
        info->name = (char*)malloc(len);
        memset(info->name,0,len);
        snprintf(info->name,len,"%s",name);
    }

    // log_d("add file1=%s:%s\n",dir,name);
    // log_d("add file2=%s:%s\n",info->dir,info->name);

    file_insertAtTail(&filemp.head,info);

    filemp.total ++ ;

    return OS_OK;
}

int file_filter_folder(const char* path)
{
    if(!strcmp(path, ".")){
        return OS_OK;
    }
    if(!strcmp(path, "..")){
        return OS_OK;
    }
    if(!strcmp_c(path, "ALiDvr")){
        return OS_OK;
    }
    if(!strcmp_c(path, "ALIDVRS2")){
        return OS_OK;
    }			
    if(!strcmp_c(path, "recycler")){
        return OS_OK;
    }
    if(!strcmp_c(path, "system volume information")){
        return OS_OK;
    }
    if(!strcmp_c(path, "System Volume Information")){
        return OS_OK;
    }	
    if(!strcmp_c(path, "thumbNail")){
        return OS_OK;
    }		
    if(strstr(path, "continue")){
        return OS_OK;
    }

    return OS_ERR;
}

int file_recursion_search_file(const char * dir)
{
    int ret          = OS_ERR;
    int filenum      = 0;
    int filetype     = 0;
	int is_right     = 0;
	DIR *dirfd		 = NULL;
	struct dirent	 *entry_T;
	char buff_T[sizeof(struct dirent) + 1024];

	char filepath[1024];
	//*********************************************************
	dirfd = opendir(dir);
	if(!dirfd){
		log_e("open dir error,%s\n",dir);
		return OS_ERR;
	}
	
	entry_T = (struct dirent *)buff_T;
	while (1)
	{
        os_task_delayus(10);
		entry_T = readdir(dirfd);
		if(!entry_T)
			break;

        memset(filepath,0,sizeof(filepath));

		if(entry_T->d_type == 4) //dir
		{
            ret = file_filter_folder(entry_T->d_name);
            if(ret == OS_OK){
                continue;
            }
			//*************************************************************
			strcpy(filepath,dir);
			strcat(filepath,"/");
			strcat(filepath,entry_T->d_name);
			
			// log_d("filepath=%s\n",filepath);
			//*************************************************************
			file_recursion_search_file(filepath);
			//*************************************************************
		}
		else //file
		{
			//*************************************************************
			strcpy(filepath,dir);
			strcat(filepath,"/");
			strcat(filepath,entry_T->d_name);

			// log_d("file=%d:%s:%s\n",filenum++,dir,filepath);
            //*************************************************************
			if(filemp.cfg.search_type == FILE_TYPE_VIDEO)
			{
				if(__Valid_VideoFileType(filepath)){
					is_right = 1;
				}else{
					is_right = 0;
				}
                filetype = FILE_TYPE_VIDEO;
			}
			else if(filemp.cfg.search_type == FILE_TYPE_PHOTO)
			{
				if(__Valid_PhotoFileType(filepath)){
					is_right = 1;
				}else{
					is_right = 0;
				}
                filetype = FILE_TYPE_PHOTO;
			}
            else if(filemp.cfg.search_type == FILE_TYPE_MUSIC)
			{
				if(__Valid_MusicFileType(filepath)){
					is_right = 1;
				}else{
					is_right = 0;
				}
                filetype = FILE_TYPE_MUSIC;
			}else{
                is_right = 1;
                if(__Valid_VideoFileType(filepath)){
                    filetype = FILE_TYPE_VIDEO;
                }else if(__Valid_PhotoFileType(filepath)){
                    filetype = FILE_TYPE_PHOTO;
                }else if(__Valid_MusicFileType(filepath)){
                    filetype = FILE_TYPE_MUSIC;
                }else{
                    filetype = FILE_TYPE_DEFAULT;
                }
            }
			//*************************************************************
			if(is_right){
                file_add_list(filetype,dir,filepath);
			}
			//*************************************************************
		}
	}
	
	closedir(dirfd);
	dirfd = NULL;
	
	return OS_OK;
}

int file_search_start(void)
{
    file_recursion_search_file(filemp.cfg.dir);

    return OS_OK;
}


static void* file_search_task(void *para)
{
    long long s_time  = 0;
    long long e_time  = 0;
    long long t_time  = 0;

    while(1)
    {
        os_task_delayms(1000);
        if(filemp.index == 0)
        {
            s_time = os_time_get_us();
            file_search_start();
            e_time = os_time_get_us();

            t_time = e_time - s_time;

            log_i("consumtime:%dus:%dms:%ds\n",t_time,t_time/1000,t_time/1000/1000);
            log_i("total file:%d\n",filemp.total);

            filemp.index = 1;
        }
        else if(filemp.index == 1)
        {
            // file_printList(filemp.head);
            file_done_end_callback();
            filemp.index = 2;
        }
        else{

        }
    }
}

int file_done_end_callback(void)
{
    if(filemp.cfg.end_search_cb)
    {
        filemp.cfg.end_search_cb((void*)(&filemp));
    }

    return OS_OK;
}

int file_search_everything(file_cfg_t* cfg)
{
    int ret = -1;

    filemp.index    = 0;
    filemp.total    = 0;
    filemp.head     = NULL;
    
    filemp.cfg.sort_type     = cfg->sort_type,
    filemp.cfg.search_type   = cfg->search_type,
    filemp.cfg.end_search_cb = cfg->end_search_cb,

    memset(filemp.cfg.dir,0,sizeof(filemp.cfg.dir));
    snprintf(filemp.cfg.dir,sizeof(filemp.cfg.dir),"%s",cfg->dir);

    log_i("search type&dir:%d:%d:%s\n",filemp.cfg.sort_type,filemp.cfg.search_type,filemp.cfg.dir);

    ret = os_task_create(&filemp.task_handle,file_search_task,NULL);
    if(ret != 0){
        log_e("err\n");
        return OS_ERR;
    }

    return OS_OK;
}
